/*
 * edbsr.c - EDB Tree Traversal
 * Clunix, cezanne@clunix.com, 2008.2
 *
 */

#include "config.h"

#include "edbd.h"
#include "edbd_conn.h"
#include "edbsr.h"
#include "edbroot.h"
#include "ecxroot.h"
#include "reactor.h"
#include "bdexpr.h"
#include "edbd_vsr.h"

#define EDBSR_GET_XXX(name, type)				\
type								\
edbsr_get_##name(edbd_conn_t edbd_conn, const sr_t *sr)		\
{								\
	conn_t	*conn = (conn_t *)edbd_conn;			\
								\
	ECMASSERT(!sr_is_vHMS(sr));				\
	sr = sr_get_real(sr);					\
	if (conn->ecxroot)					\
		sr = ecxroot_tryget_shadow_SET(conn->ecxroot, sr);	\
	return sr_get_##name(sr);				\
}

EDBSR_GET_XXX(bool, ECMBOOL)
EDBSR_GET_XXX(dbl, ecm_double)
EDBSR_GET_XXX(int, ecm_int32)
EDBSR_GET_XXX(ll, ecm_int64)
EDBSR_GET_XXX(oct_data, ecm_ptr_t)
EDBSR_GET_XXX(oct_size, ecm_size_t)
EDBSR_GET_XXX(ptr, ecm_ptr_t)
EDBSR_GET_XXX(ref, const sr_t *)
EDBSR_GET_XXX(str, const char *)
EDBSR_GET_XXX(val, sr_val_t)

static sr_t *
do_get(conn_t *conn, ecxroot_t *ecxroot, sr_t *sr, const sr_t *sr_LNP, srt_t srt_result, ECMBOOL autopin);

static sr_t *
do_get_deref(conn_t *conn, sr_t *sr)
{
	sr_t	*sr_deref;

	if (!vsr_is_ref(sr))
		return sr;
	sr_deref = edbsr_get_deref(conn, sr);
	tree_unlock(sr, PIN_LOCK);
	return sr_deref;
}

static sr_t *
add_result_1(sr_t *sr_res, sr_t *sr_child_res)
{
	if (sr_res == NULL)
		sr_res = sr_create_vHMS(sr_get_type(sr_child_res));
	if (sr_is_virtual(sr_child_res))
		sr_child_res = sr_dup(sr_child_res);
	else
		sr_child_res = sr_build_virtual(sr_child_res);

	if (!sr_mightbe_member(sr_res, sr_child_res)) {
		srt_t	srt_mbr_super;

		srt_mbr_super = srt_get_common_super(sr_get_member_type(sr_res),
						     vsr_get_type(sr_child_res));
		SR_UPCAST_VHMS_ASSERT(sr_res, srt_get_vHMS_type(srt_mbr_super));
	}

	SR_APPEND_ASSERT(sr_res, sr_child_res);
	return sr_res;
}

static sr_t *
get_all(conn_t *conn, ecxroot_t *ecxroot, sr_t *sr, sr_t *sr_LNP, srt_t srt_result, ECMBOOL autopin)
{
	sr_t	*sr_child;
	sr_t	*sr_child_res;
	sr_t	*sr_res = NULL;

	if (srt_result != ST_NULL) {
		ECMASSERT(srt_is_vHMS(srt_result));
		sr_res = sr_create(srt_result);
	}
	for (sr_child = edbsr_get_first(conn, sr, ECM_FALSE);
	     sr_child;
	     sr_child = edbsr_get_next_free(conn, sr_child)) {
		sr_child_res = do_get(conn, ecxroot, sr_child, sr_LNP, srt_result, autopin);
		if (sr_child_res == NULL)
			continue;
		if (sr_is_vHMS(sr_child_res)) {
			if (sr_res == NULL)
				sr_res = sr_child_res;
			else {
				vHMS_merge(sr_res, sr_child_res);
				sr_free(sr_child_res);
			}
		}
		else
			sr_res = add_result_1(sr_res, sr_child_res);
	}

	if (sr_res == NULL) {
		srt_t	srt = sr_get_member_type(sr);

		if ((srt = bdexpr_get_srt_with_srt(srt, sr_LNP)) != ST_NULL)
			sr_res = sr_create_vHMS(srt);
	}
	tree_unlock(sr, PIN_LOCK);
	return sr_res;
}

static sr_t *
do_get_all(conn_t *conn, ecxroot_t *ecxroot, sr_t *sr, const sr_t *sr_LNP, int idx, srt_t srt_result, ECMBOOL autopin)
{
	sr_t	*sr_subLNP;

	if (!sr_is_HMSgroup(sr)) {
		tree_unlock(sr, PIN_LOCK);
		return NULL;
	}

	sr_subLNP = get_sr_sub_LNP(sr_LNP, idx, -1);
	del_sr_sub_LNP(sr_subLNP, 0, 0);
	sr = get_all(conn, ecxroot, sr, sr_subLNP, srt_result, autopin);
	sr_free(sr_subLNP);

	return sr;
}

static sr_t *
do_get_any(conn_t *conn, sr_t *sr)
{
	sr_t	*sr_mbr;

	if (!sr_is_HMSgroup(sr)) {
		tree_unlock(sr, PIN_LOCK);
		return NULL;
	}
	sr_mbr = edbsr_get_first(conn, sr, ECM_FALSE);
	edbsr_release(sr, ECM_FALSE, ECM_FALSE);
	return sr_mbr;
}

static sr_t *
do_get_parent(conn_t *conn, sr_t *sr)
{
	sr_t	*sr_parent;

	sr_parent = edbsr_get_parent(conn, sr, ECM_FALSE);
	edbsr_release(sr, ECM_FALSE, ECM_FALSE);
	return sr_parent;
}

static sr_t *
do_get_child(conn_t *conn, ecxroot_t *ecxroot, sr_t *sr, const char *name)
{
	sr_t	*sr_child;

	sr_child = edbsr_get_child(conn, ecxroot, sr, name, ECM_FALSE);
	edbsr_release(sr, ECM_FALSE, ECM_FALSE);
	return sr_child;
}

static sr_t *
do_get(conn_t *conn, ecxroot_t *ecxroot, sr_t *sr, const sr_t *sr_LNP, srt_t srt_result, ECMBOOL autopin)
{
	sr_t	*sr_LNI;
	int	idx = 0;

	if (!tree_lock(sr, PIN_LOCK))
		return NULL;
	SR_FOREACH_CHILD(sr_LNP, "LNIs", sr_LNI) {
		if ((sr = do_get_deref(conn, sr)) == NULL)
			return NULL;

		switch (sr_getc_int(sr_LNI, "Type")) {
		case LNI_TYPE_ALL:
			return do_get_all(conn, ecxroot, sr, sr_LNP, idx, srt_result, autopin);
		case LNI_TYPE_ANY:
			sr = do_get_any(conn, sr);
			break;
		case LNI_TYPE_DOTDOT:
			sr = do_get_parent(conn, sr);
			break;
		case LNI_TYPE_NAME:
			sr = do_get_child(conn, ecxroot, sr, sr_getc_str(sr_LNI, "Name"));
			break;
		default:
			tree_unlock(sr, PIN_LOCK);
			return NULL;
		}
		if (sr == NULL)
			return NULL;
		idx++;
	}

	if (vsr_is_ref(sr) && !is_ref_sr_LNP(sr_LNP))
		sr = do_get_deref(conn, sr);

	if (sr && autopin && (sr_is_vHMS(sr) || edbroot_is_ontree(sr)))
		conn_insert_pin(conn, sr);

	return sr;
}

sr_t *
edbsr_get(edbd_conn_t edbd_conn, ecxroot_t *ecxroot, const sr_t *sr_anchor,
	  const sr_t *sr_LNP, srt_t srt_result, ECMBOOL autopin)
{
	sr_t	*sr_res;

	ECMASSERT(sr_LNP != NULL &&
		  (!autopin || edbd_conn != NULL));

	if (is_ABS_sr_LNP(sr_LNP))
		sr_anchor = sr_edbroot;
	else if (sr_anchor == NULL)
		return NULL;

	sr_res = do_get(edbd_conn, ecxroot, sr_get_real(sr_anchor), sr_LNP, srt_result, autopin);

	if (sr_res == sr_anchor && sr_is_vHMS(sr_res))
		sr_res = sr_dup(sr_anchor);
	return sr_res;
}

sr_t *
edbsr_getn(edbd_conn_t edbd_conn, const sr_t *sr_anchor, const char *LNP, ECMBOOL autopin)
{
	sr_t	*sr, *sr_LNP;

	sr_LNP = get_sr_LNP(LNP);
	sr = edbsr_get(edbd_conn, NULL, sr_anchor, sr_LNP, ST_NULL, autopin);
	sr_free(sr_LNP);
	return sr;
}

sr_t *
edbsr_get_child(edbd_conn_t edbd_conn, ecxroot_t *ecxroot,
		const sr_t *sr_group, const char *name, ECMBOOL autopin)
{
	conn_t	*conn = (conn_t *)edbd_conn;

	ECMASSERT(edbd_conn != NULL || !autopin);

	if (ecxroot == NULL && conn != NULL)
		ecxroot = conn->ecxroot;

	if (sr_is_vHMS(sr_group)) {
		sr_t	*sr;

		sr = sr_get_child(sr_group, name);
		while (edbroot_is_ontree(sr) && !tree_lock(sr, PIN_VALID_LOCK))
			sr = sr_next(sr);
		if (autopin && sr)
			edbsr_insert_pin(conn, sr);
		return sr;
	}
	else if (!edbroot_is_ontree(sr_group) &&
		 !ecxroot_is_ontree(ecxroot, sr_group))
		return vsr_get_child(sr_group, name);
	else if (ecxroot == NULL) {
		sr_t	*sr;

		sr = edbroot_getc(sr_group, name);
		if (autopin && sr)
			conn_insert_pin(conn, sr);
		return sr;
	}
	else {
		sr_t	*sr;

		sr = ecxroot_get_child(ecxroot, sr_group, name);
		if (autopin && sr && edbroot_is_ontree(sr))
			conn_insert_pin(conn, sr);
		return sr;
	}
}

sr_t *
edbsr_get_parent(edbd_conn_t edbd_conn, const sr_t *sr, ECMBOOL autopin)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	ECMASSERT((!autopin || edbd_conn != NULL) && !sr_is_vHMS(sr));

	if (!edbsr_is_ontree(conn, sr))
		return vsr_get_parent(sr);
	else if (conn == NULL || (ecxroot = conn->ecxroot) == NULL) {
		sr_t	*sr_res;

		sr_res = edbroot_get_parent(sr);
		if (autopin && sr_res)
			conn_insert_pin(conn, sr_res);
		return sr_res;
	}
	else {
		sr_t	*sr_res;

		sr_res = ecxroot_get_parent(ecxroot, sr);
		if (autopin && sr_res)
			edbsr_insert_pin(conn, sr_res);
		return sr_res;
	}
}

static sr_t *
get_valid_sr_next(conn_t *conn, sr_t *sr, ECMBOOL autopin)
{
	while (edbroot_is_ontree(sr) && !tree_lock(sr, PIN_VALID_LOCK))
		sr = sr_next(sr);
	if (autopin && sr)
		edbsr_insert_pin(conn, sr);
	return sr;
}

sr_t *
edbsr_get_first(edbd_conn_t edbd_conn, const sr_t *sr_group, ECMBOOL autopin)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	ECMASSERT(edbd_conn != NULL);

	if (sr_is_vHMS(sr_group))
		return get_valid_sr_next(conn, sr_first(sr_group), autopin);
	else if (!edbsr_is_ontree(conn, sr_group))
		return vsr_get_first(sr_group);
	else if ((ecxroot = conn->ecxroot) == NULL) {
		sr_t	*sr;

		sr = edbroot_first(sr_group);
		if (autopin && sr)
			conn_insert_pin(conn, sr);
		return sr;
	}
	else {
		sr_t	*sr;

		sr = ecxroot_get_first(ecxroot, sr_group);
		if (autopin && sr)
			edbsr_insert_pin(conn, sr);
		return sr;
	}
}

sr_t *
edbsr_get_next(edbd_conn_t edbd_conn, const sr_t *sr, ECMBOOL autopin)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	ECMASSERT(edbd_conn != NULL && !sr_is_vHMS(sr));

	if (sr_is_virtual(sr))
		return get_valid_sr_next(conn, sr_next(sr), autopin);

	if (!edbsr_is_ontree(conn, sr))
		return vsr_get_next(sr);

	if ((ecxroot = conn->ecxroot) == NULL) {
		sr_t	*sr_res;

		sr_res = edbroot_next(sr);
		if (autopin && sr_res)
			conn_insert_pin(conn, sr_res);
		return sr_res;
	}
	else {
		sr_t	*sr_res;

		sr_res = ecxroot_get_next(ecxroot, sr);
		if (autopin && sr_res)
			edbsr_insert_pin(conn, sr_res);
		return sr_res;
	}
}

sr_t *
edbsr_get_next_free(edbd_conn_t edbd_conn, const sr_t *sr)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;
	sr_t	*sr_sib;

	ECMASSERT(edbd_conn != NULL && !sr_is_vHMS(sr));

	if (!edbsr_is_ontree(conn, sr))
		return vsr_get_next(sr);

	if (conn == NULL || (ecxroot = conn->ecxroot) == NULL)
		sr_sib = edbroot_next(sr);
	else
		sr_sib = ecxroot_get_next(ecxroot, sr);
	tree_unlock(sr, PIN_LOCK);
	return sr_sib;
}

static sr_t *
get_valid_sr_prev(conn_t *conn, sr_t *sr, ECMBOOL autopin)
{
	while (edbroot_is_ontree(sr) && !tree_lock(sr, PIN_VALID_LOCK))
		sr = sr_prev(sr);
	if (autopin && sr)
		edbsr_insert_pin(conn, sr);
	return sr;
}

sr_t *
edbsr_get_last(edbd_conn_t edbd_conn, const sr_t *sr_group, ECMBOOL autopin)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	ECMASSERT(edbd_conn != NULL);

	if (sr_is_vHMS(sr_group))
		return get_valid_sr_prev(conn, sr_last(sr_group), autopin);
	else if (!edbsr_is_ontree(conn, sr_group))
		return vsr_get_last(sr_group);
	else if ((ecxroot = conn->ecxroot) == NULL) {
		sr_t	*sr;

		sr = edbroot_last(sr_group);
		if (autopin && sr)
			conn_insert_pin(conn, sr);
		return sr;
	}
	else {
		sr_t	*sr;

		sr = ecxroot_get_last(ecxroot, sr_group);
		if (autopin && sr)
			edbsr_insert_pin(conn, sr);
		return sr;
	}
}

sr_t *
edbsr_get_prev(edbd_conn_t edbd_conn, const sr_t *sr, ECMBOOL autopin)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (sr_is_virtual(sr))
		return get_valid_sr_prev(conn, sr_prev(sr), autopin);

	if (!edbsr_is_ontree(conn, sr))
		return vsr_get_prev(sr);

	if (conn == NULL || (ecxroot = conn->ecxroot) == NULL) {
		sr_t	*sr_res;

		sr_res = edbroot_prev(sr);
		if (autopin && sr_res)
			conn_insert_pin(conn, sr_res);
		return sr_res;
	}
	else {
		sr_t	*sr_res;

		sr_res = ecxroot_get_prev(ecxroot, sr);
		if (autopin && sr_res)
			edbsr_insert_pin(conn, sr_res);
		return sr_res;
	}
}

char *
edbsr_get_LNP(edbd_conn_t edbd_conn, const sr_t *sr)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (sr_is_vHMS(sr))
		return NULL;

	if (conn == NULL || (ecxroot = conn->ecxroot) == NULL)
		return edbroot_get_LNP(sr);
	else
		return ecxroot_get_LNP(ecxroot, sr);
}

sr_t *
edbsr_get_deref(edbd_conn_t edbd_conn, const sr_t *sr)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (conn == NULL || (ecxroot = conn->ecxroot) == NULL)
		return edbroot_get_deref(sr);
	else
		return ecxroot_get_deref(ecxroot, sr_get_real(sr));
}

ECMBOOL
edbsr_is_ontree(edbd_conn_t edbd_conn, const sr_t *sr)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (conn == NULL || (ecxroot = conn->ecxroot) == NULL)
		return edbroot_is_ontree(sr);
	else
 		return ecxroot_is_ontree(ecxroot, sr);
}

sr_t *
edbsr_dup(edbd_conn_t edbd_conn, const sr_t *sr_src)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	ECMASSERT(conn != NULL);

	if (!edbsr_is_ontree(conn, sr_src))
		return vsr_dup(sr_src);

	if ((ecxroot = conn->ecxroot) == NULL)
		return edbroot_dup(sr_src);
	else
		return ecxroot_dup(ecxroot, sr_src);
}

static edb_err_t
do_assign_with_vHMS(edbd_conn_t edbd_conn, sr_t *sr_assigned, sr_t *sr_operand)
{
	sr_t	*sr_child, *sr_mbr;
	const char	*name;

	if (!sr_is_HMS(sr_assigned))
		return -ERR_EDB_GENERAL;
	SR_FOREACH_CHILD(sr_operand, NULL, sr_mbr) {
		name = sr_get_name(sr_mbr);
		sr_child = edbsr_get_child(edbd_conn, NULL, sr_assigned, name, ECM_FALSE);
		if (sr_child == NULL) {
			srt_t	srt = vsr_get_type(sr_mbr);

			if (srt_is_ref(sr_get_member_type(sr_assigned)) &&
			    !srt_is_ref(srt))
				srt = srt_get_ref_type(srt);
			sr_child = edbsr_xecreate(edbd_conn, sr_assigned, name, srt);
		}
		if (sr_child == NULL)
			return -ERR_EDB_GENERAL;
		if (edbsr_assign(edbd_conn, sr_child, sr_mbr) != EDB_OK) {
			edbsr_release(sr_child, ECM_FALSE, ECM_FALSE);
			return -ERR_EDB_GENERAL;
		}
		edbsr_release(sr_child, ECM_FALSE, ECM_FALSE);
	}
	return EDB_OK;
}

edb_err_t
edbsr_assign(edbd_conn_t edbd_conn, sr_t *sr_assigned, sr_t *sr_operand)
{
	sr_val_t	val;
	edb_err_t	err;

	sr_assigned = sr_get_real(sr_assigned);
	if (sr_operand == NULL)
		return edbsr_clear_val(edbd_conn, sr_assigned);
	if (sr_is_vHMS(sr_operand))
		return do_assign_with_vHMS(edbd_conn, sr_assigned, sr_operand);
	if (sr_is_ref(sr_assigned)) {
		if (vsr_is_ref(sr_operand))
			return edbsr_set_ref(edbd_conn, sr_assigned, sr_operand);
		return edbsr_set_target(edbd_conn, sr_assigned, sr_operand);
	}
	if (sr_is_virtual(sr_operand))
		val = edbsr_cpy_val(edbd_conn, sr_operand);
	else
		val = sr_crop_val(sr_operand);
	if ((err = edbsr_set_val(edbd_conn, sr_assigned, val)) != EDB_OK)
		srv_free(vsr_get_type(sr_operand), val);
	return err;
}

edb_err_t
edbsr_set_val(edbd_conn_t edbd_conn, sr_t *sr_assigned, sr_val_t val)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (sr_assigned == NULL)
		return ECM_FALSE;

	ECMASSERT(sr_assigned != NULL && !sr_is_vHMS(sr_assigned));

	if (!edbsr_is_ontree(conn, sr_assigned)) {
		if (vsr_set_val(sr_assigned, val))
			return EDB_OK;
		else
			return -ERR_EDB_GENERAL;
	}
	if (conn == NULL || (ecxroot = conn->ecxroot) == NULL)
		return edbroot_set_val(edbd_conn, sr_assigned, val, ECM_TRUE);
	else
		return ecxroot_set_val(ecxroot, sr_assigned, val);
}

edb_err_t
edbsr_set_ref(edbd_conn_t edbd_conn, sr_t *sr, sr_t *sr_LNP)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (conn == NULL || (ecxroot = conn->ecxroot) == NULL)
		return edbroot_set_ref(edbd_conn, sr, sr_LNP, ECM_TRUE);
	else
		return ecxroot_set_ref(ecxroot, sr, sr_LNP);
}

edb_err_t
edbsr_set_target(edbd_conn_t edbd_conn, sr_t *sr, const sr_t *sr_target)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (conn == NULL || (ecxroot = conn->ecxroot) == NULL)
		return edbroot_set_target(edbd_conn, sr, sr_target, ECM_TRUE);
	else
		return ecxroot_set_target(ecxroot, sr, sr_target);
}

sr_val_t
edbsr_cpy_val(edbd_conn_t edbd_conn, sr_t *sr)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (conn != NULL && (ecxroot = conn->ecxroot) != NULL)
		return vsr_cpy_val(ecxroot_tryget_shadow_SET(ecxroot, sr));
	return vsr_cpy_val(sr);
}

edb_err_t
edbsr_clear_val(edbd_conn_t edbd_conn, sr_t *sr)
{
	sr_val_t	val;

	srv_init(vsr_get_type(sr), &val);
	return edbsr_set_val(edbd_conn, sr, val);
}

sr_t *
edbsr_xecreate(edbd_conn_t edbd_conn, sr_t *sr_HMS, const char *name, srt_t srt)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (conn == NULL || (ecxroot = conn->ecxroot) == NULL)
		return edbroot_xecreate(edbd_conn, sr_HMS, name, srt, 0, ECM_TRUE);
	else
		return ecxroot_xecreate(ecxroot, sr_HMS, name, srt);
}

sr_t *
edbsr_xeappend(edbd_conn_t edbd_conn, sr_t *sr_HMS, sr_t *sr_xe_SA)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (conn == NULL || (ecxroot = conn->ecxroot) == NULL)
		return edbroot_xeappend(edbd_conn, sr_HMS, sr_xe_SA, 0, ECM_TRUE);
	else
		return ecxroot_xeappend(ecxroot, sr_HMS, sr_xe_SA);
}

ECMBOOL
edbsr_xedelete(edbd_conn_t edbd_conn, sr_t *sr_xe, ECMBOOL force)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (conn == NULL || (ecxroot = conn->ecxroot) == NULL) {
		if (edbroot_xedelete(edbd_conn, sr_xe, ECM_TRUE, force) == EDB_OK)
			return ECM_TRUE;
		return ECM_FALSE;
	}
	else
		return ecxroot_xedelete(ecxroot, sr_xe, force);
}

int
edbsr_get_num_child(edbd_conn_t edbd_conn, const sr_t *sr_group)
{
	conn_t	*conn = (conn_t *)edbd_conn;
	ecxroot_t	*ecxroot;

	if (sr_group == NULL || !vsr_is_group(sr_group))
		return -1;
	if (!edbsr_is_ontree(conn, sr_group) || sr_is_vHMS(sr_group))
		return vsr_get_num_child(sr_group);
	else if (conn == NULL || (ecxroot = conn->ecxroot) == NULL)
		return edbroot_get_num_child(sr_group);
	else
		return ecxroot_get_num_child(ecxroot, sr_group);
}

void
edbsr_insert_pin(edbd_conn_t edbd_conn, sr_t *sr)
{
	if (edbroot_is_ontree(sr))
		conn_insert_pin(edbd_conn, sr);
}

void
edbsr_release(sr_t *sr, ECMBOOL autopin, ECMBOOL from_get)
{
	if (sr_is_vHMS(sr)) {
		if (!autopin)
			tree_unlock(sr, PIN_LOCK);
		if (from_get)
			sr_free(sr);
	}
	else {
		if (!autopin && edbroot_is_ontree(sr))
			tree_unlock(sr, PIN_LOCK);
	}
}
